/****************************************************
	文件：ResRecorder.cs
	作者：HuskyT
	邮箱：1005240602@qq.com
	日期：2020/9/27 11:59:28
	功能：资源记录器：分配资源使用ID，缓存资源
*****************************************************/

using System;
using System.Collections.Generic;
using UnityEngine;
using HTUtility;

namespace HTFramework.ResKit
{
    public class ResRecorder : Singleton<ResRecorder>
    {
        private static int mNewID;
        #region ResItem缓存
        /// <summary>
        /// ResItem的缓存
        /// </summary>
        private Dictionary<uint, ResItem> mResCache;
        /// <summary>
        /// 正在使用的ResItem的缓存
        /// </summary>
        private Dictionary<uint, ResItem> mResUsingCache;
        /// <summary>
        /// 闲置的ResItem的缓存
        /// </summary>
        private Dictionary<uint, ResItem> mResIdleCache;
        #endregion

        #region ABItem缓存
        /// <summary>
        /// ABItem的缓存
        /// </summary>
        private Dictionary<uint, ABItem> mABCache;
        /// <summary>
        /// 正在使用的ABItem的缓存
        /// </summary>
        private Dictionary<uint, ABItem> mABUsingCache;
        /// <summary>
        /// 闲置的ABItem的缓存
        /// </summary>
        private Dictionary<uint, ABItem> mABIdleCache;
        #endregion

        /// <summary>
        /// 可用于分配的资源ID，用于标记资源使用在时间上的先后顺序，后使用的ID大于先使用的
        /// </summary>
        public static int NewID
        {
            get
            {
                mNewID++;
                mNewID %= int.MaxValue;
                return mNewID;
            }
        }

        public void Init()
        {
            mNewID = -1;
            mResCache = new Dictionary<uint, ResItem>();
            mResUsingCache = new Dictionary<uint, ResItem>();
            mResIdleCache = new Dictionary<uint, ResItem>();
            mABCache = new Dictionary<uint, ABItem>();
            mABUsingCache = new Dictionary<uint, ABItem>();
            mABIdleCache = new Dictionary<uint, ABItem>();
            HTLogger.Info("ResRecorder init done.");
        }

        /// <summary>
        /// 缓存ResItem
        /// </summary>
        /// <param name="crc">ResItem路径对应的Crc</param>
        /// <param name="recorderType">缓存类型</param>
        public void RecordResItem(uint crc, ResRecorderType recorderType)
        {
            RecordResItem(GetResItem(crc), recorderType);
        }
        /// <summary>
        /// 缓存ResItem
        /// </summary>
        /// <param name="item">ResItem路径对应的Crc</param>
        /// <param name="recorderType">缓存类型</param>
        public void RecordResItem(ResItem item, ResRecorderType recorderType)
        {
            RemoveFromCache(item); //移除的时候不改变 ResItem 自身的 ResRecorderType
            AddToCache(item, recorderType); //添加的时候不改变 ResRecorderType
        }
        /// <summary>
        /// 缓存ABItem
        /// </summary>
        /// <param name="crc">ABItem ABName 对应的Crc</param>
        /// <param name="recorderType">缓存类型</param>
        public void RecordABItem(uint crc, ResRecorderType recorderType)
        {
            RecordABItem(GetABItem(crc), recorderType);
        }
        /// <summary>
        /// 缓存ABItem
        /// </summary>
        /// <param name="item">ABItem ABName 对应的Crc</param>
        /// <param name="recorderType">缓存类型</param>
        public void RecordABItem(ABItem item, ResRecorderType recorderType)
        {
            RemoveFromCache(item); //移除的时候不改变 ABItem 自身的 ResRecorderType
            AddToCache(item, recorderType); //添加的时候不改变 ResRecorderType
        }

        public ResItem GetResItem(string path)
        {
            return GetResItem(CRC32.GetCrc32(path));
        }
        public ResItem GetResItem(uint crc)
        {
            ResItem item = null;
            if (mResCache.TryGetValue(crc, out item) == false || item == null)
            {
                HTLogger.Error("Can not find resItem from cache. crc : {0}", crc);
                return null;
            }
            return item;
        }
        public ABItem GetABItem(string abName)
        {
            return GetABItem(CRC32.GetCrc32(abName));
        }
        public ABItem GetABItem(uint crc)
        {
            ABItem item = null;
            if (mABCache.TryGetValue(crc, out item) == false || item == null)
            {
                HTLogger.Error("Can not find abItem from cache. crc : {0}", crc);
                return null;
            }
            return item;
        }


        #region Private Function
        /// <summary>
        /// 添加到对应的缓存中
        /// </summary>
        /// <param name="item">ResItem</param>
        /// <param name="recorderType">缓存类型</param>
        private void AddToCache(ResItem item, ResRecorderType recorderType)
        {
            switch (recorderType)
            {
                case ResRecorderType.UNLOADED:
                    if (mResUsingCache.ContainsKey(item.Crc))
                    {
                        HTLogger.Debug("{0} 从 mResUsingCache 中移除", item.AssetName);
                        mResUsingCache.Remove(item.Crc);
                    }
                    if (mResIdleCache.ContainsKey(item.Crc))
                    {
                        HTLogger.Debug("{0} 从 mResIdleCache 中移除", item.AssetName);
                        mResIdleCache.Remove(item.Crc);
                    }
                    if (mResCache.ContainsKey(item.Crc) == false)
                    {
                        HTLogger.Debug("{0} 添加到 mResCache 中", item.AssetName);
                        mResCache.Add(item.Crc, item);
                    }
                    break;
                case ResRecorderType.USING:
                    if (mResUsingCache.ContainsKey(item.Crc))
                    {
                        HTLogger.Error("ResUsingCache already contains the crc，Res path : {0}", item.Path);
                    }
                    else
                    {
                        HTLogger.Debug("{0} 添加到 mResUsingCache 中", item.AssetName);
                        mResUsingCache.Add(item.Crc, item);
                    }
                    break;
                case ResRecorderType.IDLE:
                    if (mResIdleCache.ContainsKey(item.Crc))
                    {
                        HTLogger.Error("ResIdleCache already contains the crc，Res path : {0}", item.Path);
                    }
                    else
                    {
                        HTLogger.Debug("{0} 添加到 mResIdleCache 中", item.AssetName);
                        mResIdleCache.Add(item.Crc, item);
                    }
                    break;
            }
        }
        /// <summary>
        /// 添加到对应的缓存中
        /// </summary>
        /// <param name="item">ABItem</param>
        /// <param name="recorderType">缓存类型</param>
        private void AddToCache(ABItem item, ResRecorderType recorderType)
        {
            switch (recorderType)
            {
                case ResRecorderType.UNLOADED:
                    if (mABUsingCache.ContainsKey(item.Crc))
                    {
                        HTLogger.Debug("{0} 从 mABUsingCache 中移除", item.ABName);
                        mABUsingCache.Remove(item.Crc);
                    }
                    if (mABIdleCache.ContainsKey(item.Crc))
                    {
                        HTLogger.Debug("{0} 从 mABIdleCache 中移除", item.ABName);
                        mABIdleCache.Remove(item.Crc);
                    }
                    if (mABCache.ContainsKey(item.Crc) == false)
                    {
                        HTLogger.Debug("{0} 添加到 mABCache 中", item.ABName);
                        mABCache.Add(item.Crc, item);
                    }
                    break;
                case ResRecorderType.USING:
                    if (mABUsingCache.ContainsKey(item.Crc))
                    {
                        HTLogger.Error("ABUsingCache already contains the crc，AB Name : {0}", item.ABName);
                    }
                    else
                    {
                        HTLogger.Debug("{0} 添加到 mABUsingCache 中", item.ABName);
                        mABUsingCache.Add(item.Crc, item);
                    }
                    break;
                case ResRecorderType.IDLE:
                    if (mABIdleCache.ContainsKey(item.Crc))
                    {
                        HTLogger.Error("ABIdleCache already contains the crc，AB Name : {0}", item.ABName);
                    }
                    else
                    {
                        HTLogger.Debug("{0} 添加到 mABIdleCache 中", item.ABName);
                        mABIdleCache.Add(item.Crc, item);
                    }
                    break;
            }
        }
        /// <summary>
        /// 从ResItem当前缓存中移除
        /// </summary>
        /// <param name="item">ResItem</param>
        private void RemoveFromCache(ResItem item)
        {
            switch (item.RecorderType)
            {
                case ResRecorderType.DEFAULT:
                    break;
                case ResRecorderType.UNLOADED:
                    break;
                case ResRecorderType.USING:
                    if (mResUsingCache.ContainsKey(item.Crc))
                    {
                        HTLogger.Debug("{0} 从 mResUsingCache 中移除", item.AssetName);
                        mResUsingCache.Remove(item.Crc);
                    }
                    break;
                case ResRecorderType.IDLE:
                    if (mResIdleCache.ContainsKey(item.Crc))
                    {
                        HTLogger.Debug("{0} 从 mResIdleCache 中移除", item.AssetName);
                        mResIdleCache.Remove(item.Crc);
                    }
                    break;
            }
        }
        /// <summary>
        /// 从ABItem当前缓存中移除
        /// </summary>
        /// <param name="item">ABItem</param>
        private void RemoveFromCache(ABItem item)
        {
            switch (item.RecorderType)
            {
                case ResRecorderType.DEFAULT:
                    break;
                case ResRecorderType.UNLOADED:
                    break;
                case ResRecorderType.USING:
                    if (mABUsingCache.ContainsKey(item.Crc))
                    {
                        HTLogger.Debug("{0} 从 mABUsingCache 中移除", item.ABName);
                        mABUsingCache.Remove(item.Crc);
                    }
                    break;
                case ResRecorderType.IDLE:
                    if (mABIdleCache.ContainsKey(item.Crc))
                    {
                        HTLogger.Debug("{0} 从 mABIdleCache 中移除", item.ABName);
                        mABIdleCache.Remove(item.Crc);
                    }
                    break;
            }
        }
        #endregion


        #region For Test
        /// <summary>
        /// 打印指定缓存中的信息
        /// </summary>
        /// <param name="recorderType">缓存类型</param>
        public void LogRecorder(ResRecorderType recorderType)
        {
            switch (recorderType)
            {
                case ResRecorderType.UNLOADED:
                    LogResCache(mResCache, "打印 mResCache");
                    LogABCache(mABCache, "打印 mABCache");
                    break;
                case ResRecorderType.USING:
                    LogResCache(mResUsingCache, "打印 mResUsingCache");
                    LogABCache(mABUsingCache, "打印 mABUsingCache");
                    break;
                case ResRecorderType.IDLE:
                    LogResCache(mResIdleCache, "打印 mResIdleCache");
                    LogABCache(mABIdleCache, "打印 mABIdleCache");
                    break;
                case ResRecorderType.MAX:
                    break;
            }
        }
        private void LogResCache(Dictionary<uint, ResItem> cache, string title)
        {
            HTLogger.Warning("//----" + title + "：");
            foreach (ResItem item in cache.Values)
            {
                HTLogger.Debug("Name : {0} , RefCount : {1} , Path : {2}\nABName : {3}", item.AssetName, item.RefCount, item.Path, item.ABName);
            }
        }
        private void LogABCache(Dictionary<uint, ABItem> cache, string title)
        {
            HTLogger.Warning("//----" + title + "：");
            foreach (ABItem item in cache.Values)
            {
                HTLogger.Debug("ABName : {0} , RefCount : {1}", item.ABName, item.RefCount);
            }
        }
        #endregion
    }
}
